﻿using System;
using System.Globalization;
using System.Linq;
using Sustainalytics.Synchronization.Interface;
using Sustainalytics.DataLayer;
using MongoDB.Driver;
using MongoDB.Bson;
using Sustainalytics.ClientDW.Entities;

namespace Sustainalytics.CarbonData.BussinesLogic
{
    public class CarbonDataSyncStep : ISyncStep
    {
        public SyncStepOrder ExecutionOrder { get { return SyncStepOrder.SyncCarbonData; } }

        public SyncContext Start(SyncContext syncContext)
        {
            syncContext.Log("Starting CarbonData syncronization at " + DateTime.UtcNow.ToString(CultureInfo.InvariantCulture));
            
            var inputFile = ReadLatestInputFileHistory(syncContext);
            
            if (inputFile == null)
            {
                syncContext.Log("Stoping CarbonData syncronization, No input file!");
                return syncContext;
            }

            var fileRepository = new FileRepository(syncContext.GAConnectionStrings["ClientPlatform"]);

            var lastOrDefault = inputFile.History.LastOrDefault();

            if (lastOrDefault == null)
            {
                syncContext.Log("Stoping CarbonData syncronization, No history!");
                return syncContext;
            }

            var fileStatus = lastOrDefault.Status;
            if (fileStatus != UploadStatus.UploadValid)
            {
                syncContext.Log("Stoping CarbonData syncronization, No valid upload!");
                return syncContext;
            }

            var fileTuple = fileRepository.ReadFileAsStream(inputFile.Id);

            if (fileTuple == null || fileTuple.Item1 == null)
            {
                syncContext.Log("Stoping CarbonData syncronization, No file stream!");
                return syncContext;
            }

            try
            {
                inputFile.History.Add(new InputHistory()
                {
                    DateTime = DateTime.UtcNow,
                    Status = UploadStatus.AppliedStart
                });


                var excelFileImport = new ExcelFileImport(syncContext.GAConnectionStrings["ClientDW"]);
                
                var result = excelFileImport.Import(fileTuple.Item1);


                inputFile.History.Add(new InputHistory()
                {
                    DateTime = DateTime.UtcNow,
                    Status = UploadStatus.AppliedSuccess,
                    Details = result.Details
                });

                UpdateCorporateDataHasCarbonDataFlag(syncContext);
            }
            catch (Exception ex)
            {
                inputFile.History.Add(new InputHistory()
                {
                    DateTime = DateTime.UtcNow,
                    Status = UploadStatus.AppliedFailure,
                    Details = ex.ToString()
                });
                Console.WriteLine(ex);

                syncContext.Log(string.Format("Exception: {0}", ex));
            }
            finally
            {
                syncContext.AddChange(new ChangedElement()
                {
                    AffectedDocument = inputFile,
                    AffectedCollection = inputFile.GetType().Name,
                    AffectedDB = syncContext.GAConnectionStrings["ClientPlatform"],
                    AffectedDocumentId = inputFile.Id,
                    AffectedDocumentType = inputFile.GetType(),
                    AffectedObjectName = ChangedElement.AFFECTED_INPUT_FILE_NAME_OBJECT,
                    ChangeTimestamp = DateTime.Now,
                });
            }

            return syncContext;
        }

        private void UpdateCorporateDataHasCarbonDataFlag(SyncContext syncContext)
        {
            // reset HasCarbonDataResearch in CorporateData
            var database = MongoDatabaseFactory.GetDatabase(syncContext.GAConnectionStrings["ClientDW"]);

            var collection = database.GetCollection<CorporateData>(typeof(CorporateData).Name);

            //var filter = Builders<CorporateData>.Filter.Eq(cd => cd.HasCarbonDataResearch, true);
            //var update = Builders<CorporateData>.Update.Set(cd => cd.HasCarbonDataResearch, false);

            //collection.UpdateMany(filter, update);


            // get PUCarbonData from CorporateData
            var puCarbonData = collection.Find(cd => cd.PUCarbonData && cd.ResearchParentId == null)
                .Project(cd => cd.Id).ToList();

            // get CarbonData companies
            var carbonDataCollection = database.GetCollection<CarbonData>(typeof(CarbonData).Name);

            var ids = carbonDataCollection.Find(new BsonDocument()).Project(cd => cd.Id).ToList();

            // intersect CarbonData companies with PUCarbonData
            var companyIds = ids.Intersect(puCarbonData);


            // update HasCarbonDataResearch in CorporateData

            //var builder = Builders<CorporateData>.Filter;
            //filter = builder.In(cd => cd.Id, ids);

            //update = Builders<CorporateData>.Update.Set(cd => cd.HasCarbonDataResearch, true);
            
            //collection.UpdateMany(filter, update);

            // log HasCarbonDataResearch companies
            //var hasCarbonDataResearch = collection.Find(cd => cd.HasCarbonDataResearch).Project(cd => cd.Id).ToList();
            //syncContext.Log(string.Format("{0} Companies with HasCarbonDataResearch", hasCarbonDataResearch.Count));
        }

        public CarbonDataInputFile ReadLatestInputFileHistory(SyncContext syncContext)
        {
            var inputFile = MongoDatabaseFactory
                .GetDatabase(syncContext.GAConnectionStrings["ClientPlatform"])
                .GetCollection<CarbonDataInputFile>(typeof(CarbonDataInputFile).Name)
                .Find(new BsonDocument())
                .Sort(Builders<CarbonDataInputFile>.Sort.Descending("History.DateTime"))
                .Limit(1)
                .FirstOrDefault();

            return inputFile;
        }

        public void Cancel()
        {
            throw new NotImplementedException();
        }

        public void Abort()
        {
            throw new NotImplementedException();
        }
    }
}
